﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;

namespace nwrole.lib {
    public class StandardServiceProvider : IServiceProvider {

        public event NwroleSettingsChangedHandler SupervisorSettingsChangedEvent;
        public event NwroleSettingsChangedHandler ServiceSettingsChangedEvent;

        public void Start() {
            CreateSupervisorConfigWatcher();

            foreach(string serviceName in GetServiceNames())
            {
                CreateServiceConfigWatcher(serviceName);
            }
        }

        public string[] GetServiceNames() {
            string servicesDir = ServicesDirectory;
            if (!Directory.Exists(servicesDir))
                Directory.CreateDirectory(servicesDir);

            List<string> serviceNames = new List<string>();

            foreach (string serviceDir in Directory.EnumerateDirectories(servicesDir)) {
                serviceNames.Add(Path.GetFileName(serviceDir));
            }

            return serviceNames.ToArray();
        }

        public PropertyList LoadSupervisorSettings() {
            string supervisorConfig = SupervisorConfig;
            if (File.Exists(SupervisorConfig)) {
                PropertyList plist = new PropertyList(supervisorConfig);
                return plist;
            }

            return null;
        }

        public void SaveSupervisorSettings(PropertyList plist) {
            plist.Save(SupervisorConfig);
        }

        public PropertyList LoadServiceSettings(string serviceName) {
            string serviceDir = Path.Combine(ServicesDirectory, serviceName);
            string configPath = Path.Combine(serviceDir, "service-config.xml");

            try {
                if (File.Exists(configPath)) {
                    PropertyList plist = new PropertyList(configPath);
                    return plist;
                }
            } catch {
                
            }

            return null;
        }

        public void SaveServiceSettings(PropertyList plist, string serviceName) {
            //string serviceDir = Path.Combine(ServicesDirectory, serviceName);
            //string configPath = Path.Combine(serviceDir, "service-config.xml");

            string configPath = GetServiceConfig(serviceName);

            plist.Save(configPath);
        }

        private static string ApplicationDirectory {
            get {
                return Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
            }
        }

        private static string ServicesDirectory {
            get {
                return Path.Combine(ApplicationDirectory, "Services");
            }
        }

        private static string SupervisorConfig {
            get {
                return Path.Combine(ApplicationDirectory, "supervisor-config.xml");
            }
        }

        private static string GetServiceDirectory(string serviceName)
        {
            return Path.Combine(ServicesDirectory, serviceName);
        }

        private static string GetServiceConfig(string serviceName)
        {
            return Path.Combine(GetServiceDirectory(serviceName), "service-config.xml");
        }

        public Dictionary<string, object> GetPluginProviderSettings() {
          return new Dictionary<string, object>();
        }

        private void CreateSupervisorConfigWatcher()
        {
            // Create a new FileSystemWatcher and set its properties.
            FileSystemWatcher watcher = new FileSystemWatcher();
            watcher.Path = Path.GetDirectoryName(SupervisorConfig);

            watcher.NotifyFilter = NotifyFilters.LastWrite;

            watcher.Filter = Path.GetFileName(SupervisorConfig);

            // Add event handlers.
            watcher.Changed += new FileSystemEventHandler(OnSupervisorConfigChanged);

            // Begin watching.
            watcher.EnableRaisingEvents = true;
        }

        private void OnSupervisorConfigChanged(object source, FileSystemEventArgs e)
        {
            if(SupervisorSettingsChangedEvent != null)
                SupervisorSettingsChangedEvent(this, new NwroleSettingsChangedEventArgs() { Name = "Supervisor" });
            // Specify what is done when a file is changed, created, or deleted.
            //Console.WriteLine("File: " + e.FullPath + " " + e.ChangeType);
        }

        private void CreateServiceConfigWatcher(string serviceName)
        {
            string configPath = GetServiceConfig(serviceName);

            // Create a new FileSystemWatcher and set its properties.
            FileSystemWatcher watcher = new FileSystemWatcher();
            watcher.Path = Path.GetDirectoryName(configPath);

            watcher.NotifyFilter = NotifyFilters.LastWrite;

            watcher.Filter = Path.GetFileName(configPath);

            // Add event handlers.
            watcher.Changed += new FileSystemEventHandler(OnServiceConfigChanged);

            // Begin watching.
            watcher.EnableRaisingEvents = true;
        }

        private void OnServiceConfigChanged(object source, FileSystemEventArgs e)
        {
            if (ServiceSettingsChangedEvent != null)
            {
                string serviceName = Path.GetFileName(Path.GetDirectoryName(e.FullPath));
                ServiceSettingsChangedEvent(this, new NwroleSettingsChangedEventArgs() {Name = serviceName});
            }
            // Specify what is done when a file is changed, created, or deleted.
            //Console.WriteLine("File: " + e.FullPath + " " + e.ChangeType);
        }

        public void PulseService(Guid id, string serviceName, string message)
        {
            try
            {
                using (SupervisorDbEntities context = new SupervisorDbEntities())
                {
                    SupervisorDbService service = context.SupervisorDbServices.SingleOrDefault(s => s.Id == id);
                    if (service == null)
                    {
                        service = new SupervisorDbService() { Id = id };
                        context.SupervisorDbServices.AddObject(service);
                    }

                    service.Name = serviceName;
                    service.LastPulseMessage = message;
                    service.LastPulseDate = DateTime.UtcNow;

                    context.SaveChanges();
                }
            }
            catch (Exception e)
            {
                Trace.TraceError("StandardServiceProvider PulseService error: " + e);
                throw;
            }
        }

        public void PulsePlugin(Guid id, string pluginName, string message)
        {
            try
            {
                using (SupervisorDbEntities context = new SupervisorDbEntities())
                {
                    SupervisorDbPlugin plugin = context.SupervisorDbPlugins.SingleOrDefault(s => s.Id == id);
                    if (plugin == null)
                    {
                        plugin = new SupervisorDbPlugin() { Id = id };
                        context.SupervisorDbPlugins.AddObject(plugin);
                    }

                    plugin.DisplayName = pluginName;
                    plugin.LastPulseMessage = message;
                    plugin.LastPulseDate = DateTime.UtcNow;

                    context.SaveChanges();
                }
            }
            catch(Exception e)
            {
                Trace.TraceError("StandardServiceProvider PulsePlugin error: " + e);
                throw;
            }
        }

        public ServicePulse GetServicePulse(Guid serviceId)
        {
            using (SupervisorDbEntities context = new SupervisorDbEntities())
            {
                SupervisorDbService service = context.SupervisorDbServices.SingleOrDefault(s => s.Id == serviceId);
                if(service != null && service.LastPulseDate.HasValue)
                    return new ServicePulse() { Date = service.LastPulseDate.Value, Message = service.LastPulseMessage, ServiceId = serviceId };
            }

            return null;
        }

        public PluginPulse GetPluginPulse(Guid pluginId)
        {
            using (SupervisorDbEntities context = new SupervisorDbEntities())
            {
                SupervisorDbPlugin plugin = context.SupervisorDbPlugins.SingleOrDefault(s => s.Id == pluginId);
                if(plugin != null && plugin.LastPulseDate.HasValue)
                    return new PluginPulse() { Date = plugin.LastPulseDate.Value, Message = plugin.LastPulseMessage, PluginId = pluginId };
            }

            return null;
        }
    }
}
